package com.wuye.web.system.service.impl;

import com.wuye.utils.JwtUtils;
import com.wuye.utils.RedisConstant;
import com.wuye.utils.Result;
import com.wuye.utils.SystemConstant;
import com.wuye.web.system.entity.LiveUser;
import com.wuye.web.system.entity.LoginParam;
import com.wuye.web.system.entity.SysUser;
import com.wuye.web.system.service.LoginService;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

@Service
public class LoginServiceImpl implements LoginService {
    //spring security中的认证管理器用来对登录请求进行处理
    @Resource
    private AuthenticationManager authenticationManager;
    @Resource
    private RedisTemplate<String,Object> redisTemplate;
    @Resource
    private JwtUtils jwtUtils;
    @Override
    public Result login(LoginParam loginParam) {
        //校验验证码
        validCaptcha(loginParam.getCaptchaId(),loginParam.getCaptchaCode());
        //在Spring Security中，通过Authentication来封装用户的验证请求信息
        //通过自定义函数validUsernameAndPassword完成对用户名和密码的校验
        Authentication authentication = validUsernameAndPassword(loginParam.getUsername(),loginParam.getUserType(),loginParam.getPassword());
        //通过自定义函数responseToken将用户信息存入redis，并响应token数据
        return responseToken(loginParam.getUserType(),authentication);
    }

    private Result responseToken(Integer userType, Authentication authentication) {
        int userId;
        String username;
        if (userType == SystemConstant.USER_TYPE_YEZHU){
            //authentication封装着用户的验证请求信息，其中，principal 是认证的主体信息，通常为用户名或者用户对象
            LiveUser liveUser = (LiveUser) authentication.getPrincipal();
            userId = liveUser.getUserId();
            username = liveUser.getUsername();
            //将业主信息存入redis中
            redisTemplate.opsForValue().set(RedisConstant.LOGIN_LIVE_USER_PRE + userId,liveUser);
        }else {
            SysUser sysUser = (SysUser) authentication.getPrincipal();
            userId = sysUser.getUserId();
            username = sysUser.getUsername();
            redisTemplate.opsForValue().set(RedisConstant.LOGIN_SYSTEM_USER_PRE + userId, sysUser, RedisConstant.LOGIN_SYSTEM_USER_EXPIRE_TIME, TimeUnit.MINUTES);
        }

        //将token响应给前端
        String token = jwtUtils.generateToken(userId,username,userType);
        Map<String,String> map = new HashMap<>();
        map.put("token",token);
        return Result.success(map);
    }

    //验证所输入的用户名和密码是否正确
    private Authentication validUsernameAndPassword(String username, Integer userType, String password) {
        username = username + ":" + userType;
        //UsernamePasswordAuthenticationToken 是 Spring Security 中用于封装用户名密码认证信息的一个类，它实现了 Authentication 接口，用于表示一个认证请求
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken
            = new UsernamePasswordAuthenticationToken(username,password);
        Authentication authentication = authenticationManager.authenticate(usernamePasswordAuthenticationToken);
        if (Objects.isNull(authentication)){
            throw new RuntimeException("用户名或密码错误");
        }
        return authentication;
    }
    //校验验证码的函数
    private void validCaptcha(String captchaId, String captchaCode) {
        //通过传进来的验证码id在redis中查取对应的验证码码值
        String captchaCode_redis = (String)redisTemplate.opsForValue().get(RedisConstant.CAPTCHA_PRE + captchaId);
        //将两个码值进行比对
        if (!captchaCode_redis.equalsIgnoreCase(captchaCode)){throw new RuntimeException("验证码错误");}
    }

    public Result logout(){
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        Object user = authentication.getPrincipal();
        if (user instanceof LiveUser){
            LiveUser liveUser = (LiveUser) user;
            redisTemplate.delete(RedisConstant.LOGIN_LIVE_USER_PRE+liveUser.getUserId());
        }else {
            SysUser sysUser = (SysUser) user;
            redisTemplate.delete(RedisConstant.LOGIN_SYSTEM_USER_PRE+sysUser.getUserId());
        }
        return Result.success();
    }
}
